#pragma once

// -----------------------------------------------------------------------------

#include <shlwapi.h>

// the following include file is located at:
//    C:\Program Files\Microsoft SDKs\Windows\v6.0\Include
#include <ktmw32.h>

#include "Win32.IO.File.h"
#include "Win32.Diagnostics.Result.h"
#include "Win32.String.h"

namespace Kif
{
namespace Win32
{
namespace IO
{
namespace Ktm
{

// -----------------------------------------------------------------------------

class Transaction
{
private:
   HANDLE handle;
public:

   inline HANDLE GetHandle()
   {  return handle; }

   bool BeginTransaction();

   inline void Dispose()
   {
      if (handle == INVALID_HANDLE_VALUE)
         CloseHandle(handle);
      handle = INVALID_HANDLE_VALUE;
   }

   inline bool CommitTransaction()
   {
      BOOL done = ::CommitTransaction(handle);
      return(done == TRUE);
   }

   inline bool RollbackTransaction()
   {
      BOOL done = ::RollbackTransaction(handle);
      Dispose();
      return(done == TRUE);
   }

   Transaction()
   {
      handle = INVALID_HANDLE_VALUE;
   }
  ~Transaction()
   {
      Dispose();
   }
   
}  ;  // end of Transaction

// -----------------------------------------------------------------------------

/// <summary>information about an open file</summary>
class TransactedTextFile
{
private:
   Transaction *pTransaction;

private:

   TCHAR *lastErrorMessage;
   Kif::Win32::Diagnostics::Result lastResult;

   HANDLE   hFile;             // file handler

   /// <summary>Open given file for read and write</summary>
   /// <param name="path">file path name</param>
   /// <param name="dwDesiredAccess">desired access</paarm>
   /// <param name="dwShareMode">shared mode</paarm>
   /// <param name="dwCreationDisposition">creation disposition</paarm>
   /// <return>true is returned if operation was completed</returns>
   inline bool Open(
      TCHAR *path,
      DWORD dwDesiredAccess,
      DWORD dwShareMode,
      DWORD dwCreationDisposition)
   {
      lastResult.Clear();
      if (path == NULL)
      {
         lastResult.ErrorNo = ERROR_INVALID_DATA;
         return(false);
      }

      // open file for read and write
      hFile = CreateFileTransacted(
         path,
         dwDesiredAccess,                     // desired access
         dwShareMode,                         // shared access
         NULL,                                // specify default security
         dwCreationDisposition,               // creation disposition
         FILE_ATTRIBUTE_NORMAL |
         FILE_FLAG_SEQUENTIAL_SCAN,           // flags and attributes
         NULL,                                // template file
         pTransaction->GetHandle(),           // transaction Handle
         NULL,                                // PUSHORT pusMiniVersion
         NULL);                               // PVOID LpExtendedParameter

      if (hFile == INVALID_HANDLE_VALUE)
         lastResult.ErrorNo = GetLastError();

      return(hFile != INVALID_HANDLE_VALUE);
   }  // end of OpenReadWrite

public:

   inline Kif::Win32::Diagnostics::Result *GetLastResult()
   {
      return(&lastResult);
   }  // end of GetLastResult

   /// <summary>close and release resources</summary>
   void Close()
   {
      if (hFile != INVALID_HANDLE_VALUE)
         CloseHandle(hFile);
      hFile = INVALID_HANDLE_VALUE;
      lastResult.Clear();
   }  // end of Close

   // --------------------------------------------------------------------------

   TransactedTextFile(Transaction *pTransaction)
   {
      if (pTransaction == NULL)
         throw _T("TransactedTextFile::TransactedTextFile: ")
               _T("NULL pTransaction not supported");
      this->pTransaction = pTransaction;
      hFile = INVALID_HANDLE_VALUE;
   }  // end of TextFile (ctor)

  ~TransactedTextFile()
   {
      Close();
   }  // end of TextFile (dtor)

   // --------------------------------------------------------------------------

   /// <summary>Create given file. The file will only be created you will need
   /// to open it later.</summary>
   /// <param name="path">file path name</param>
   /// <return>true is returned if operation was completed</returns>
   inline bool Create(TCHAR *path)
   {
      // open file for read and write
      bool done = Open(
         path,
         FILE_SHARE_DELETE |
         GENERIC_READ | GENERIC_WRITE,        // desired access
         FILE_SHARE_READ | FILE_SHARE_WRITE,  // shared access
         CREATE_ALWAYS);                      // creation disposition

      // on creation always close the file
      if (done)
         Close();
      return(done);
   }  // end of Create

   inline bool Create(Kif::Win32::String *path)
   {
      if (path == NULL)
      {
         lastResult.ErrorNo = ERROR_INVALID_DATA;
         return(false);
      }
      return(Create(path->GetBuffer()));
   }  // end of Create

   inline bool Create(Kif::Win32::String &path)
   {
      return(Create(path.GetBuffer()));
   }  // end of Create

   // --------------------------------------------------------------------------

   /// <summary>Open given file for read and write</summary>
   /// <param name="path">file path name</param>
   /// <return>true is returned if operation was completed</returns>
   inline bool OpenReadWrite(TCHAR *path)
   {
      Kif::Win32::IO::File file;
      if (!file.Exists(path))
      {
         if (!Create(path))
            return(false);
      }

      // open file for read and write
      bool done = Open(path,
         GENERIC_READ | GENERIC_WRITE,        // desired access
         FILE_SHARE_READ | FILE_SHARE_WRITE,  // shared access
         OPEN_EXISTING);                      // creation disposition

      // position the cursor to the end-of-file
      if (done)
      {
         DWORD dw = SetFilePointer(hFile,0,NULL,FILE_END);
      }

      return(done);
   }  // end of OpenReadWrite

   inline bool OpenReadWrite(Kif::Win32::String *path)
   {
      if (path == NULL)
      {
         lastResult.ErrorNo = ERROR_INVALID_DATA;
         return(false);
      }
      return(OpenReadWrite(path->GetBuffer()));
   }  // end of OpenReadWrite

   inline bool OpenReadWrite(Kif::Win32::String &path)
   {
      return(OpenReadWrite(path.GetBuffer()));
   }  // end of OpenReadWrite

   // --------------------------------------------------------------------------

   /// <summary>Open given file for read only</summary>
   /// <param name="path">file path name</param>
   /// <return>true is returned if operation was completed</returns>
   inline bool OpenRead(TCHAR *path)
   {
      // open file for read and write
      bool done = Open(path,
         GENERIC_READ,        // desired access
         FILE_SHARE_READ,     // shared access
         OPEN_EXISTING);      // creation disposition

      return(done);
   }  // end of OpenRead

   inline bool OpenRead(Kif::Win32::String *path)
   {
      if (path == NULL)
      {
         lastResult.ErrorNo = ERROR_INVALID_DATA;
         return(false);
      }
      return(OpenRead(path->GetBuffer()));
   }  // end of OpenRead

   inline bool OpenRead(Kif::Win32::String &path)
   {
      return(OpenRead(path.GetBuffer()));
   }  // end of OpenRead

   // --------------------------------------------------------------------------

}  ;  // end of TransactedTextFile


}  // end of Kif::Win32::IO::Ktm
}  // end of Kif::Win32::IO
}  // end of Kif::Win32
}  // end of Kif

